<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue'
import { onBeforeRouteLeave, useRoute } from 'vue-router'
import ProcessFirstForm from './components/form.vue'
import ProcessFirstFormResult from './components/result.vue'
import ProcessTabFormAndResult from './components/tab/index.vue'
import { formConfig } from './config'
import { getCases } from '@/api/cases'
import router from '@/routes'
import useStore from '@/stores'
import { useFetch } from '@/composables/useFetch'
import { CASE_STATUS } from '@/config/map'
import { isEmptyObject } from '@/utils'
import { useDebounceFn } from '@/composables/useDebounce'

const route = useRoute()
const { cases } = useStore()
cases.setCaseProcess(formConfig.processes)

const typeComponent = {
  ProcessFirstForm,
  ProcessFirstFormResult,
  ProcessTabFormAndResult,
}

type componentType = keyof typeof typeComponent
const currentComponent = ref<componentType>('ProcessFirstForm')
const currentComponentRef = ref()
const currentStep = ref(1)
const caseLayoutContentRef = ref()
const hasResult = computed(() => cases.caseInfo?.status === CASE_STATUS.HAS_RESULT)

// 页面请求
const { data: caseInfo, loading: detailLoading, error: detailError, execute: getCaseDetailExecute } = useFetch((parmas: any = {}) => getCases(parmas))

getCaseInfo()

// 获取case信息
async function getCaseInfo() {
  const caseId = route.query.id
  if (!caseId) {
    const path = route.matched[0].path
    router.push({
      path,
    })
    return
  }

  await getCaseDetailExecute({ caseId })
  cases.setCaseInfo(caseInfo.value)
  initStepsInfo()
}

// 监听ws通知
watch(() => cases.wsNotifyEndStatus, async (nVal: boolean) => {
  if (nVal) {
    // 通知完立即设置为false，方便下次通知
    cases.setWsNotifyEndStatus(false)
    // 更新case状态和初始化steps
    await getCaseInfo()
    // 默认获取当前步骤的结果（没有点击或者点击第一步的时候，获取caculation result数据）
    const step = currentStep.value < 2 ? 2 : currentStep.value
    onClickChangeStepAction(step)
  }
})

// 步骤切换的时候需要重置steps的更新状态(没有缓存的时候，再次点击高亮区域需要重新加载)
watch(() => currentStep.value, () => {
  cases.setCaseProcessUpdate()
})

// 初始化步骤条高亮信息
function initStepsInfo() {
  // 没有结果就不更新步骤条
  const { jsonArgs } = caseInfo.value
  if (!hasResult.value)
    return

  // 有结果后和skip字段一起判断是否高亮
  const detailData = jsonArgs ? JSON.parse(jsonArgs) : null
  const fiveSteps = ['Caculation Result']
  const somSteps = ['SOM']
  const sensitiveSteps = ['Sensitivity analysis']
  const optimizatoinSteps = ['Optimization']
  const contributionSteps = ['Contribution']
  if (detailData && !isEmptyObject(detailData)) {
    // 标记有更新, 不论运行哪一步fiveSteps一定要运行，因此默认标记finish, 其他步骤需要判断skip
    cases.setCaseProcessUpdate()
    cases.updateCaseProcess(fiveSteps)
    const { SOM, Contribution, Optimization, Sensitivity_analysis } = detailData
    cases.updateCaseProcess(somSteps, SOM.skip ? 'wait' : 'finish')
    cases.updateCaseProcess(sensitiveSteps, Sensitivity_analysis.skip ? 'wait' : 'finish')
    cases.updateCaseProcess(optimizatoinSteps, Optimization.skip ? 'wait' : 'finish')
    cases.updateCaseProcess(contributionSteps, Contribution.skip ? 'wait' : 'finish')
  }
}

// 切换步骤条获取最新数据结果
function onClickChangeStepAction(data: number) {
  // 滚动到顶部
  caseLayoutContentRef.value?.scrollTo(0, 0)
  // 记录当前步骤，运行后随时更新steps
  currentStep.value = data
  cases.setCurrentStepNumber(data)
  // 1 代表填写表单页面
  // 2 代表运行结果页面
  // 剩余步骤 代表其他步骤页面
  const selectStep = 1
  const secondStep = 2
  const currentStepItem = cases.caseProcess.find((_item: any, index: number) => index === data - 1)
  if (data === selectStep) {
    currentComponent.value = 'ProcessFirstForm'
  }
  else if (data === secondStep) {
    currentComponent.value = 'ProcessFirstFormResult'
    nextTick(() => {
      getLatestData(currentStepItem)
    })
  }
  else {
    currentComponent.value = 'ProcessTabFormAndResult'
    nextTick(() => {
      currentComponentRef.value?.initTabForm()
      getLatestData(currentStepItem)
    })
  }
}

function getLatestData(currentStepItem: any) {
  const finishStatus = currentStepItem?.status === 'finish'
  const field = currentStepItem?.title
  const stepsUpdateMap = cases.processUpdate as any

  // 有结果 成功状态 有最新数据还没更新情况下去更新(没缓存的情况下，切换step需要重置更新状态)
  // 更新完成后设置步骤更新为false，表示已经更新过了
  if (hasResult.value && finishStatus && stepsUpdateMap[field]) {
    currentComponentRef.value?.onClickRefreshAllAction()
    cases.setCaseProcessUpdate({ [field]: false })
  }
}

function onClickBackAction() {
  if (currentComponent.value === 'ProcessFirstForm')
    router.push({ path: '/cases/index' })

  else
    currentComponent.value = _getBackComponentStr()
}

const debounceRun = useDebounceFn(onClickRunAction, 1000)
function onClickRunAction() {
  switch (currentComponent.value) {
    case 'ProcessFirstForm':
      currentComponentRef.value?.onClickSubmitForm().then(() => {
        caseLayoutContentRef.value?.scrollTo(0, 0)
        currentComponent.value = 'ProcessFirstFormResult'
        // 页面渲染出来后直接运行
        nextTick(() => {
          onClickRunAction()
        })
      })
      break
    case 'ProcessFirstFormResult':
      currentComponentRef.value?.onClickRunFiveStep()
      break
    case 'ProcessTabFormAndResult':
      currentComponentRef.value?.onClickRunTabStep()
      break
  }
}

function _getBackComponentStr() {
  let backIndex = 0
  Object.keys(typeComponent).forEach((key: string, index: number) => {
    if (key === currentComponent.value)
      backIndex = index - 1
  })
  return Object.keys(typeComponent)[backIndex] as componentType
}

onBeforeRouteLeave((to, from) => {
  // 不是父页面清空query，是的话返回时直接从query的pageInfo回填
  const matchedParentPage = from.matched.some((item: any) => to.path === item.path || to.path === item?.redirect)
  if (!matchedParentPage) {
    to.query = from.query = {}
  }
  else {
    const { pageNo, pageSize } = route.query
    to.query = from.query = { pageNo, pageSize }
  }
  // 路径中的fullpath会携带query信息path不会，去除掉id信息后的path同步给fullPath
  to.fullPath = to.path
  from.fullPath = from.path
  // 清空保存的case数据
  cases.RESET_STATE()
})
</script>

<template>
  <div class="case-layout">
    <div class="case-layout__header">
      <div class="title">
        <GpBreadcrumb />
      </div>
      <div class="operator">
        <a-button @click="onClickBackAction">
          Back
        </a-button>
        <a-button type="primary" :loading="cases.caseRunLoading" @click="debounceRun">
          Run
        </a-button>
      </div>
    </div>
    <GpLoading :loading="detailLoading" :empty="detailError" type="skeleton">
      <div class="process">
        <a-steps size="small" :initial="1" label-placement="vertical" @change="onClickChangeStepAction">
          <a-step
            v-for="(item, index) in cases.caseProcess"
            :key="index"
            :icon="item.icon"
            :status="item.status"
          >
            <template #title>
              <span :class="{ 'selected-step': index === currentStep - 1 }">{{ item.title }}</span>
            </template>
          </a-step>
        </a-steps>
      </div>
      <div ref="caseLayoutContentRef" class="case-layout__content">
        <!-- 重型组件使用缓存 -->
        <!-- NOTE：缓存会很卡，不缓存就需要重新发送请求数据 -->
        <!-- <keep-alive> -->
        <component
          :is="typeComponent[currentComponent]"
          ref="currentComponentRef"
          v-model:run="currentComponent"
          :current-step="currentStep"
        />
        <!-- </keep-alive> -->
      </div>
    </GpLoading>
  </div>
</template>

<style lang="less" scoped>
.case-layout {
  &__header {
    display: flex;
    align-items: center;
    padding: 15px 20px;
    background: @color-page-header;
    // box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
    // z-index: 1;

    .title {
      flex: 1;
      font-size: @font-size-large;
      font-family: Web_SemiBold;
    }

    .operator {
      flex: 2;
      display: flex;
      flex-direction: row-reverse;
      column-gap: 10px;
      align-items: center;
      flex-wrap: wrap;
      .secondbtn {
        color: @color-theme-second;
        border-color: @color-theme-second;
      }
    }
  }

  .process {
    padding: 20px 20px 10px;
    box-shadow: 0 8px 16px 0 rgba(28,31,33,.1);
    overflow-x: auto;
    ::v-deep(.selected-step) {
      background-color: @color-sidemenu-sub;
      color: #fff;
      padding: 0 2px;
    }
  }

  &__content {
    // height: calc(100vh - 82px - 62px - 165px);
    height: calc(100vh - -60px - 62px - 20px - 62px - 117px - 120px);
    overflow-y: auto;
    padding: 15px 25px;
  }

  ::v-deep(.ant-steps .ant-steps-item-finish>.ant-steps-item-container>.ant-steps-item-content>.ant-steps-item-title) {
    color: @color-sidemenu-sub;
  }
}
</style>
